using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using BTSXPath = Microsoft.BizTalk.XPath;
using MapTestFramework.Common.Tests.Transforms;
using System.Xml;

namespace MapTestFramework.Common.Tests
{
    [TestClass]
    public class TestHelperFixture
    {
        #region Constructor And Initializing Members

        public TestHelperFixture()
        {
            return;
        }

        #endregion

        #region Additional test attributes

        // [ClassInitialize()]
        // public static void ClassInitialize(TestContext testContext) { }
        // [ClassCleanup()]
        // public static void ClassCleanup() { }
        [TestInitialize()]
        public void TestInitialize() 
        {
            m_Mocks = new MockRepository();
            m_Listener = m_Mocks.PartialMock<TextWriterTraceListener>();
            System.Diagnostics.Trace.Listeners.Add(Listener);

            m_Helper = new TestHelper(
                new TestableMapBaseMapExecuter(new Schema1_To_Schema2()), 
                m_SourcePathBase, m_ExpectedPathBase
                );
            m_Helper.TestExecuted += new
                EventHandler<TestEventArgs>(HandleTestExecuted);
            m_Helper.TestExecuting += new
                EventHandler<TestEventArgs>(HandleTestExecuting);

            if (File.Exists(GetSourcePath()))
                File.Delete(GetSourcePath());
            if (File.Exists(GetActualPath()))
                File.Delete(GetActualPath());
            if (File.Exists(GetExpectedPath()))
                File.Delete(GetExpectedPath());
            if (File.Exists(GetActualOriginalPath()))
                File.Delete(GetActualOriginalPath());
            return;
        }
        [TestCleanup()]
        public void TestCleanup() 
        {
            System.Diagnostics.Trace.Listeners.Clear();
            m_Helper.TestExecuted -= new
                EventHandler<TestEventArgs>(HandleTestExecuted);
            m_Helper.TestExecuting -= new
                EventHandler<TestEventArgs>(HandleTestExecuting);
            return;
        }

        #endregion

        #region Test Members

        #region GetActualPath

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetActualPathPathNull()
        {
            try
            {
                TestHelper.GetActualPath(null, "Name");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("path", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: path",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetActualPathPathEmpty()
        {
            try
            {
                TestHelper.GetActualPath(string.Empty, "Name");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("path", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: path",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetActualPathNameNull()
        {
            try
            {
                TestHelper.GetActualPath("Dummy", null);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetActualPathNameEmpty()
        {
            try
            {
                TestHelper.GetActualPath("Dummy", string.Empty);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }

        #endregion

        #region GetExpectedPath

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetExpectedPathPathNull()
        {
            try
            {
                TestHelper.GetExpectedPath(null, "Name");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("path", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: path",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetExpectedPathPathEmpty()
        {
            try
            {
                TestHelper.GetExpectedPath(string.Empty, "Name");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("path", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: path",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetExpectedPathNameNull()
        {
            try
            {
                TestHelper.GetExpectedPath("Dummy", null);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetExpectedPathNameEmpty()
        {
            try
            {
                TestHelper.GetExpectedPath("Dummy", string.Empty);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }

        #endregion

        #region GetSourcePath

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetSourcePathPathNull()
        {
            try
            {
                TestHelper.GetSourcePath(null, "Name");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("path", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: path",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetSourcePathPathEmpty()
        {
            try
            {
                TestHelper.GetSourcePath(string.Empty, "Name");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("path", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: path",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetSourcePathNameNull()
        {
            try
            {
                TestHelper.GetSourcePath("Dummy", null);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetSourcePathNameEmpty()
        {
            try
            {
                TestHelper.GetSourcePath("Dummy", string.Empty);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }

        #endregion

        #region TestMap

        [TestMethod]
        public void TestBase()
        {
            this.ExecuteTestMapBase();
            return;
        }
        [TestMethod]
        public void TestBaseDifferentNotation()
        {
            m_Helper.ExpectedPathBase = "Schema2DifferentNotation.xml";
            this.ExecuteTestMapBase();
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestBaseNameNull()
        {
            try
            {
                this.ExecuteTestMapBase(null);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual(
                    "name", ex.ParamName, "Invalid parameter name"
                    );
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name", 
                    ex.Message, "Invalid exception message"
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestBaseNameEmpty()
        {
            try
            {
                this.ExecuteTestMapBase(string.Empty);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual(
                    "name", ex.ParamName, "Invalid parameter name"
                    );
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: name",
                    ex.Message, "Invalid exception message"
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        public void TestBaseFilesExistAndReadOnly()
        {
            CreateReadonlyFile(GetSourcePath());
            CreateReadonlyFile(GetActualPath());
            CreateReadonlyFile(GetExpectedPath());

            this.ExecuteTestMapBase();
            return;
        }

        #endregion

        #region TestMap with MapTestCollection

        [TestMethod]
        public void TestMapElementSingleTestCaseSingle()
        {
            ExecuteTestMapTestCases(
                "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']",
                "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']",
                new string[1][] { new string[] { "1" } }, new string[1][] { new string[] { "1" } }
                );
            return;
        }
        [TestMethod]
        public void TestMapElementSingleTestCaseMultiple()
        {
            ExecuteTestMapTestCases(
                "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']",
                "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']",
                new string[3][] { new string[] { "1" }, new string[] { "2" }, new string[] { "3" } },
                new string[3][] { new string[] { "1" }, new string[] { "2" }, new string[] { "3" } }
                );
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(NUnit.Framework.AssertionException))]
        public void TestMapElementSingleTestCaseMultipleError()
        {
            string sourceXPath = "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']";
            string expectedXPath = "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']";
            try
            {
                ExecuteTestMapTestCases(
                    sourceXPath, expectedXPath,
                    new string[3][] { new string[] { "1" }, new string[] { "2" }, new string[] { "3" } }, 
                    new string[3][] { new string[] { "1" }, new string[] { "3" }, new string[] { "3" } } 
                    );
            }
            catch (NUnit.Framework.AssertionException)
            {
                string sourcePath = "Schema1TestName2.xml";
                string expectedPath = "Schema2TestName2_Expected.xml";
                string actualPath = "Schema2TestName2_Actual.xml";
                string actualOriginalPath = "Schema2TestName2_Actual_Unformatted.xml";
                Assert.IsTrue(File.Exists(sourcePath));
                Assert.IsTrue(File.Exists(actualPath));
                Assert.IsTrue(File.Exists(actualOriginalPath));
                Assert.IsTrue(File.Exists(expectedPath));

                Assert.AreEqual(
                    "2",
                    XmlHelper.GetSingleNodeOrThrowException(sourceXPath, sourcePath).InnerXml,
                    "Source file not correctly updated"
                    );
                Assert.AreEqual(
                    "3",
                    XmlHelper.GetSingleNodeOrThrowException(expectedXPath, expectedPath).InnerXml,
                    "Expected file not correctly updated"
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        public void TestMapElementMultipleTestCaseSingle()
        {
            ExecuteTestMapTestCases(
                new string[] { 
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne1' and namespace-uri()='']",
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne2' and namespace-uri()='']",
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne3' and namespace-uri()='']"
                },
                new string[] {
                    "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_MultipleToOne' and namespace-uri()='']"
                },
                new string[1][] { new string[] { "true", "true", "true" } },
                new string[1][] { new string[] { "Field_MultipleToOne_0" } }
                );
            return;
        }
        [TestMethod]
        public void TestMapElementMultipleTestCaseMultiple()
        {
            ExecuteTestMapTestCases(
                new string[] { 
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne1' and namespace-uri()='']",
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne2' and namespace-uri()='']",
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne3' and namespace-uri()='']"
                },
                new string[] {
                    "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_MultipleToOne' and namespace-uri()='']"
                },
                new string[8][] { 
                    new string[] { "true", "true", "true" },
                    new string[] { "true", "true", "false" },
                    new string[] { "true", "false", "true" },
                    new string[] { "true", "false", "false" },
                    new string[] { "false", "true", "true" },
                    new string[] { "false", "true", "false" },
                    new string[] { "false", "false", "true" },
                    new string[] { "false", "false", "false" }
                    },
                new string[8][] { 
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_1" },
                    new string[] { "Field_MultipleToOne_1" },
                    new string[] { "Field_MultipleToOne_2" },
                    new string[] { "Field_MultipleToOne_3" }
                    }
                );
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(NUnit.Framework.AssertionException))]
        public void TestMapElementMultipleTestCaseMultipleError()
        {
            string[] sourceXPaths = new string[] { 
                "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne1' and namespace-uri()='']",
                "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne2' and namespace-uri()='']",
                "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_MultipleToOne' and namespace-uri()='']/*[local-name()='Field_MultipleToOne3' and namespace-uri()='']"
                };
            string[] expectedXPaths = new string[] {
                "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_MultipleToOne' and namespace-uri()='']"
                };
            string[][] sourceValues = new string[8][] { 
                    new string[] { "true", "true", "true" },
                    new string[] { "true", "true", "false" },
                    new string[] { "true", "false", "true" },
                    new string[] { "true", "false", "false" },
                    new string[] { "false", "true", "true" },
                    new string[] { "false", "true", "false" },
                    new string[] { "false", "false", "true" },
                    new string[] { "false", "false", "false" }
                };
            string[][] expectedValues = new string[8][] { 
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_1" },
                    new string[] { "Field_MultipleToOne_0" },
                    new string[] { "Field_MultipleToOne_2" },
                    new string[] { "Field_MultipleToOne_3" }
                };

            try
            {
                ExecuteTestMapTestCases(
                    sourceXPaths, expectedXPaths, sourceValues, expectedValues
                    );
            }
            catch (NUnit.Framework.AssertionException)
            {
                string sourcePath = "Schema1TestName6.xml";
                string expectedPath = "Schema2TestName6_Expected.xml";
                string actualPath = "Schema2TestName6_Actual.xml";
                string actualOriginalPath = "Schema2TestName6_Actual_Unformatted.xml";
                Assert.IsTrue(File.Exists(sourcePath));
                Assert.IsTrue(File.Exists(actualPath));
                Assert.IsTrue(File.Exists(actualOriginalPath));
                Assert.IsTrue(File.Exists(expectedPath));
                for (int j = 0; j < sourceXPaths.Length; j++)
                {
                    Assert.AreEqual(
                        sourceValues[5][j],
                        XmlHelper.GetSingleNodeOrThrowException(sourceXPaths[j], sourcePath).InnerXml,
                        "Source file not correctly updated"
                        );
                }

                Assert.AreEqual(
                    "Field_MultipleToOne_0",
                    XmlHelper.GetSingleNodeOrThrowException(expectedXPaths[0], expectedPath).InnerXml,
                    "Expected file not correctly updated"
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void TestMapNameNull()
        {
            try
            {
                MapTestCases collection = new MapTestCases(
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']",
                    "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']"
                    );
                collection.AddTestCase(null, null);
                collection.AddTestCase(
                    new string[] { "NewValue" }, new string[] { "NewValue" }
                    );

                m_Helper.TestMap(null, collection);
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("name", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value cannot be null.\r\nParameter name: name", 
                    ex.Message, "Invalid error message"
                    );
                throw ex;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void TestMapCollectionNull()
        {
            try
            {
                MapTestCases collection = null;
                m_Helper.TestMap(m_TestName, collection);
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("collection", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value cannot be null.\r\nParameter name: collection",
                    ex.Message, "Invalid error message"
                    );
                throw ex;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestInvalidTestCaseCount()
        {
            try
            {
                MapTestCases collection = new MapTestCases(
                    "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']",
                    "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_OneToOne_Optional' and namespace-uri()='']/*[local-name()='Field_OneToOne' and namespace-uri()='']"
                    );
                collection.AddTestCase(null, null);
                collection.AddTestCase(
                    new string[] { "NewValue" }, new string[] { "NewValue" }
                    );
                collection.SourceTestCaseValues.Add(new string[] { "NewValue2" });

                m_Helper.TestMap(m_TestName, collection);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("collection", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Testcase count for source and expected values does not match.\r\nParameter name: collection", ex.Message, "Invalid error message");
                throw ex;
            }
            return;
        }
        [TestMethod]
        public void TestMapChangeSourceFileOnTestName()
        {
            ExecuteTestMapTestCases(
                "/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Field_CurrentDateToValue' and namespace-uri()='']",
                "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_CurrentDateToValue' and namespace-uri()='']",
                new string[1][] { new string[] { "Dummy" } }, new string[1][] { new string[] { "Field_CurrentDateToValue_1" } },
                "TestMapChangeSourceFileOnTestName"
                );
            return;
        }

        #endregion

        #endregion

        #region Helper Members

        private static void CreateReadonlyFile(string path)
        {
            if (File.Exists(path))
            {
                File.SetAttributes(path, FileAttributes.Archive);
                File.Delete(path);
            }
            using (File.Create(path)) { }
            File.SetAttributes(path, FileAttributes.ReadOnly);
            return;
        }

        private const string m_ExpectedPathBase = "Schema2.xml";
        private const string m_SourcePathBase = "Schema1.xml";
        private const string m_TestName = "TestName";

        private TestHelper m_Helper;
        private TextWriterTraceListener m_Listener;
        private MockRepository m_Mocks;

        private TextWriterTraceListener Listener
        {
            get { return m_Listener; }
        }
        private MockRepository Mocks
        {
            get { return m_Mocks; }
        }

        private void CheckForWhitespace(string sourcePath, string xpathEmpty)
        {
            using (BTSXPath.XPathReader reader = new BTSXPath.XPathReader(
                    sourcePath, xpathEmpty
                    )
                )
            {
                int recordCount = 0;
                while (reader.ReadUntilMatch())
                {
                    Assert.IsTrue(
                        reader.IsEmptyElement,
                        "Element contains whitespace."
                        );
                    recordCount++;
                }
                if (recordCount == 0)
                {
                    Assert.Fail("Record not found.");
                }
            }
            return;
        }
        private void ExecuteTestMapBase()
        {
            this.ExecuteTestMapBase(m_TestName);
            return;
        }
        private void ExecuteTestMapBase(string testName)
        {
            SetupMockForTracing(
                new string[] {
                    "---------------------------------------------------",
                    string.Format("Starting test {0}", testName),
                    "---------------------------------------------------",
                    "Source file: " + Path.GetFullPath(this.GetSourcePath()),
                    "Expected file: " + Path.GetFullPath(this.GetExpectedPath()),
                    "Actual file: " + Path.GetFullPath(this.GetActualPath()),
                    "Actual unformatted file: " + Path.GetFullPath(this.GetActualOriginalPath()),
                    "---------------------------------------------------",
                    string.Format("Completed test {0}", testName),
                    "---------------------------------------------------"
                    }
                );
            this.Mocks.ReplayAll();

            m_Helper.TestMap(testName);

            Assert.IsTrue(File.Exists(GetSourcePath()));
            Assert.IsTrue(File.Exists(GetActualPath()));
            Assert.IsTrue(File.Exists(GetActualOriginalPath()));
            Assert.IsTrue(File.Exists(GetExpectedPath()));

            // Check for actual file without empty element formatting
            Assert.IsTrue(File.Exists(this.GetActualOriginalPath()), "Original actual file does not exist");

            this.Mocks.VerifyAll();

            this.CheckForWhitespace(GetActualPath(),
                "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_Attributes' and namespace-uri()='']"
                );
            this.CheckForWhitespace(GetExpectedPath(),
                "/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Record_Attributes' and namespace-uri()='']"
                );

            return;
        }
        private void ExecuteTestMapTestCases(string sourceXPath, string expectedXPath, string[][] sourceValues, string[][] expectedValues)
        {
            this.ExecuteTestMapTestCases(new string[] { sourceXPath }, new string[] { expectedXPath }, sourceValues, expectedValues);
            return;
        }
        private void ExecuteTestMapTestCases(string sourceXPath, string expectedXPath, string[][] sourceValues, string[][] expectedValues, string testName)
        {
            this.ExecuteTestMapTestCases(new string[] { sourceXPath }, new string[] { expectedXPath }, sourceValues, expectedValues, testName);
            return;
        }
        private void ExecuteTestMapTestCases(string[] sourceXPath, string[] expectedXPath, string[][] sourceValues, string[][] expectedValues)
        {
            MapTestCases collection = new MapTestCases(
                sourceXPath, expectedXPath
                );
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            m_Helper.TestMap(m_TestName, collection);

            if (sourceValues.Length == 1)
            {
                Assert.IsTrue(File.Exists(GetSourcePath()));
                Assert.IsTrue(File.Exists(GetActualPath()));
                Assert.IsTrue(File.Exists(GetActualOriginalPath()));
                Assert.IsTrue(File.Exists(GetExpectedPath()));
            }
            else
            {
                string expectedPath = string.Empty;
                for (int i = 0; i < sourceValues.Length; i++)
                {
                    string sourcePath = string.Format("Schema1TestName{0}.xml", (i + 1));
                    expectedPath = string.Format("Schema2TestName{0}_Expected.xml", (i + 1));
                    string actualPath = string.Format("Schema2TestName{0}_Actual.xml", (i + 1));
                    string actualOriginalPath = string.Format("Schema2TestName{0}_Actual_Unformatted.xml", (i + 1));
                    Assert.IsTrue(File.Exists(sourcePath));
                    Assert.IsTrue(File.Exists(actualPath));
                    Assert.IsTrue(File.Exists(actualOriginalPath));
                    Assert.IsTrue(File.Exists(expectedPath));
                    for (int j = 0; j < sourceXPath.Length; j++)
                    {
                        Assert.AreEqual(
                            sourceValues[i][j],
                            XmlHelper.GetSingleNodeOrThrowException(sourceXPath[j], sourcePath).InnerXml,
                            "Source file not correctly updated"
                            );
                    }
                }
                Assert.AreEqual(
                    expectedValues[expectedValues.Length - 1][0],
                    XmlHelper.GetSingleNodeOrThrowException(expectedXPath[0], expectedPath).InnerXml,
                    "Expected file not correctly updated"
                    );
            }
        }
        private void ExecuteTestMapTestCases(string[] sourceXPath, string[] expectedXPath, string[][] sourceValues, string[][] expectedValues, string testName)
        {
            MapTestCases collection = new MapTestCases(
                sourceXPath, expectedXPath
                );
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            m_Helper.TestMap(testName, collection);

            if (sourceValues.Length == 1)
            {
                Assert.IsTrue(File.Exists(GetSourcePath(testName)));
                Assert.IsTrue(File.Exists(GetActualPath(testName)));
                Assert.IsTrue(File.Exists(GetExpectedPath(testName)));
            }
            else
            {
                string expectedPath = string.Empty;
                for (int i = 0; i < sourceValues.Length; i++)
                {
                    string sourcePath = string.Format("Schema1{0}{1}.xml", testName, (i + 1));
                    expectedPath = string.Format("Schema2{0}{1}_Expected.xml", testName, (i + 1));
                    string actualPath = string.Format("Schema2{0}{1}_Actual.xml", testName, (i + 1));
                    Assert.IsTrue(File.Exists(sourcePath));
                    Assert.IsTrue(File.Exists(actualPath));
                    Assert.IsTrue(File.Exists(expectedPath));
                    for (int j = 0; j < sourceXPath.Length; j++)
                    {
                        Assert.AreEqual(
                            sourceValues[i][j],
                            XmlHelper.GetSingleNodeOrThrowException(sourceXPath[j], sourcePath).InnerXml,
                            "Source file not correctly updated"
                            );
                    }
                }
                Assert.AreEqual(
                    expectedValues[expectedValues.Length - 1][0],
                    XmlHelper.GetSingleNodeOrThrowException(expectedXPath[0], expectedPath).InnerXml,
                    "Expected file not correctly updated"
                    );
            }
        }
        private string GetActualOriginalPath()
        {
            return TestHelper.GetActualUnformattedPath(this.GetActualPath());
        }
        private string GetActualPath()
        {
            return TestHelper.GetActualPath(m_Helper.ExpectedPathBase, m_TestName);
        }
        private string GetActualPath(string testName)
        {
            return TestHelper.GetActualPath(m_Helper.ExpectedPathBase, testName);
        }
        private string GetExpectedPath()
        {
            return TestHelper.GetExpectedPath(m_Helper.ExpectedPathBase, m_TestName);
        }
        private string GetExpectedPath(string testName)
        {
            return TestHelper.GetExpectedPath(m_Helper.ExpectedPathBase, testName);
        }
        private string GetSourcePath()
        {
            return TestHelper.GetSourcePath(m_Helper.SourcePathBase, m_TestName);
        }
        private string GetSourcePath(string testName)
        {
            return TestHelper.GetSourcePath(m_Helper.SourcePathBase, testName);
        }
        private void SetupMockForTracing(string[] messages)
        {
            foreach (string message in messages)
            {
                Expect.Call(
                    delegate {
                        this.Listener.WriteLine(message);
                        }
                    );
            }
            return;
        }

        #endregion

        #region Event Handlers

        private void HandleTestExecuting(object sender, TestEventArgs e)
        {
            if (e.TestName == "TestMapChangeSourceFileOnTestName")
            {
                const string xpathDateTime = @"/*[local-name()='Root' and namespace-uri()='http://MySampleProject.Schemas.Schema1']/*[local-name()='Field_CurrentDateToValue' and namespace-uri()='']";
                XmlHelper.UpdateNodes(xpathDateTime,
                    DateTime.Now.ToString("yyyy-MM-dd"), e.SourcePath, e.SourcePath
                    );
            }
            return;
        }
        private void HandleTestExecuted(object sender, TestEventArgs e)
        {
            const string xpathDateTime = @"/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_CurrentDate' and namespace-uri()='']";
            XmlHelper.UpdateNodes(xpathDateTime,
                DateTime.Now.ToString("yyyyMMdd"), e.ExpectedPath, e.ExpectedPath
                );

            const string xpathDateTimeFull = @"/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_CurrentDateTime' and namespace-uri()='']";
            DateTime fullDateTime = DateTime.Parse(
                XmlHelper.GetSingleNodeOrThrowException(xpathDateTimeFull, e.OutputPath).InnerXml,
                CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal
                );
            Assert.IsTrue((fullDateTime >= e.StartDateTime), "DateTime value does not exceed StartDateTime");
            Assert.IsTrue((fullDateTime <= DateTime.Now), "DateTime value exceeds DateTime.Now");
            XmlHelper.RemoveNodes(xpathDateTimeFull, e.OutputPath, e.OutputPath);

            const string xpathGuidNode = @"/*[local-name()='Root2' and namespace-uri()='http://MySampleProject.Schemas.Schema2']/*[local-name()='Field_Guid' and namespace-uri()='']";
            System.Guid dummy = new Guid(XmlHelper.GetSingleNodeOrThrowException(xpathGuidNode, e.OutputPath).InnerXml);
            XmlHelper.UpdateNodes(xpathGuidNode,
                "{C483351A-C038-49a5-954C-3AF00AE2D71A}", e.OutputPath,
                e.OutputPath
                );
            return;
        }

        #endregion
    }
}
